package com.eight.cloud.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.eight.cloud.admin.entity.UserEntity;
import com.eight.cloud.admin.entity.UserRoleEntity;
import com.eight.cloud.admin.mapper.PermissionMapper;
import com.eight.cloud.admin.mapper.RoleMapper;
import com.eight.cloud.admin.mapper.UserMapper;
import com.eight.cloud.admin.mapper.UserRoleMapper;
import com.eight.cloud.admin.model.dto.UserDto;
import com.eight.cloud.admin.model.vo.UserDetail;
import com.eight.cloud.admin.service.IPermissionService;
import com.eight.cloud.admin.service.IRoleDeptService;
import com.eight.cloud.admin.service.IUserService;
import com.eight.cloud.core.global.constant.UserTypeEnum;
import com.eight.cloud.core.utils.supply.UserContext;
import com.eight.cloud.mybatisplus.entity.TenantDataScopeEntity;
import com.eight.cloud.core.global.exception.CustomException;
import com.eight.cloud.core.global.model.LoginUser;
import com.eight.cloud.core.global.model.SysRole;
import com.eight.cloud.mybatisplus.service.BaseService;
import com.eight.cloud.core.global.result.ResultCode;
import com.eight.cloud.core.utils.quick.RSAUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author TXC
 * @since 2024-10-02
 */
@Slf4j
@Service
public class UserServiceImpl extends BaseService<UserMapper, UserEntity> implements IUserService {
    @Resource
    private PermissionMapper permissionMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private IRoleDeptService roleDeptService;
    @Resource
    private IPermissionService permissionService;
    @Resource
    private UserRoleMapper userRoleMapper;

    @Override
    public LoginUser getUserDetails(String username, String tenantId) {
        UserEntity user = baseMapper.selectOne(lambdaQueryWrapper()
                .and(e -> e.eq(UserEntity::getUsername, username).or().eq(UserEntity::getWorkNumber, username))
                .eq(StrUtil.isNotBlank(tenantId), UserEntity::getTenantId, tenantId)
                .isNull(StrUtil.isBlank(tenantId), UserEntity::getTenantId));
        return getUserDetails(user);
    }

    @Override
    public LoginUser getUserDetails(UserEntity user) {
        if (ObjectUtil.isNotNull(user)) {
            LoginUser userDetails = convertToObject(user, LoginUser.class);
            List<SysRole> roles = roleMapper.getRoleByUserId(user.getUuid());
            roles.forEach(role -> {
                role.setPermissions(permissionMapper.getSysPermissionByRoleId(role.getUuid()));
                role.setDeptIds(roleDeptService.getDeptIds(role, userDetails));
            });
            userDetails.setUserType(UserTypeEnum.USER);
            userDetails.setRoles(roles);
            userDetails.setPermissions(permissionService.getUserPermissionMap(userDetails));
            return userDetails;
        }
        return null;
    }

    @Override
    public UserEntity register(UserDto userInfo) {
        checkUserExist(userInfo);
        String password = RSAUtils.decrypt(userInfo.getPassword());
        log.info("username: {}, password: {}, encryptPassword: {}", userInfo.getUsername(), password,
                userInfo.getPassword());
        userInfo.setPassword(passwordEncoder.encode(password));
        UserEntity user = new UserEntity();
        BeanUtils.copyProperties(userInfo, user);
        baseMapper.insert(user);
        return user;
    }

    @Override
    public UserEntity addUser(UserDto userinfo) {
        userinfo.setTenantId(UserContext.getUser().getTenantId());
        checkUserExist(userinfo);
        String password = RSAUtils.decrypt(userinfo.getPassword());
        userinfo.setPassword(passwordEncoder.encode(password));
        UserEntity user = new UserEntity();
        BeanUtils.copyProperties(userinfo, user);
        if (ObjectUtil.isNull(user.getDeptId())) {
            user.setDeptId(UserContext.getUser().getDeptId());
        }
        baseMapper.insert(user);
        return user;
    }

    private void checkUserExist(UserDto userInfo) {
        UserEntity oldUser = baseMapper.selectOne(lambdaQueryWrapper()
                .eq(UserEntity::getUsername, userInfo.getUsername())
                .eq(StrUtil.isNotBlank(userInfo.getTenantId()), TenantDataScopeEntity::getTenantId,
                        userInfo.getTenantId())
                .isNull(StrUtil.isBlank(userInfo.getTenantId()), TenantDataScopeEntity::getTenantId));
        if (ObjectUtil.isNotNull(oldUser)) {
            throw new CustomException(ResultCode.USER_ACCOUNT_ALREADY_EXIST);
        }
        oldUser = baseMapper.selectOne(lambdaQueryWrapper().eq(UserEntity::getTelephone, userInfo.getTelephone())
                .eq(StrUtil.isNotBlank(userInfo.getTenantId()), TenantDataScopeEntity::getTenantId,
                        userInfo.getTenantId())
                .isNull(StrUtil.isBlank(userInfo.getTenantId()), TenantDataScopeEntity::getTenantId));
        if (ObjectUtil.isNotNull(oldUser)) {
            throw new CustomException(ResultCode.PHONE_ALREADY_EXIST);
        }
    }

    @Override
    public UserDetail getUserDetails() {
        LoginUser loginUser = UserContext.getUser();
        if (ObjectUtil.isNotNull(loginUser)) {
            UserDetail userDetail = new UserDetail();
            BeanUtils.copyProperties(loginUser, userDetail);
            userDetail.setRoles(loginUser.getRoles().stream().map(SysRole::getCode).collect(Collectors.toList()));
            userDetail.setPermissions(loginUser.obtainPermissionsMap());
            return userDetail;
        }
        return null;
    }

    @Override
    public IPage<UserEntity> getUserList(IPage<UserEntity> page) {
        return baseMapper.selectUserList(page);
    }

    @Override
    public boolean empower(String id, List<String> roleIds) {
        AtomicInteger count = new AtomicInteger();
        roleIds.forEach(roleId -> {
            UserRoleEntity roleEntity = new UserRoleEntity();
            roleEntity.setRoleId(id);
            roleEntity.setRoleId(roleId);
            userRoleMapper.insert(roleEntity);
            count.getAndIncrement();
        });
        return count.get() > 0;
    }

    @Override
    public boolean editUser(String id, UserDto userInfo) {
        UserEntity oldUser = baseMapper.selectOne(lambdaQueryWrapper().eq(UserEntity::getId, id));
        if (ObjectUtil.isNull(oldUser)) {
            throw new CustomException(ResultCode.USER_ACCOUNT_NOT_EXIST);
        }
        if (ObjectUtil.isNotEmpty(userInfo.getPassword())) {
            String password = RSAUtils.decrypt(userInfo.getPassword());
            userInfo.setPassword(passwordEncoder.encode(password));
        }
        UserEntity user = convertToEntity(userInfo);
        user.setUuid(id);
        return updateByUuid(user);
    }


    @Override
    public void truncate() {
        baseMapper.truncate();
    }
}
